#include <gl\glew.h>
#include "Control2D.h"

#include <wx\wx.h>
#include <wx\glcanvas.h>

extern void InitExtensions();
extern bool _supportShaders;

void wxGLRenderer::CreateContext(void *control, void *context)
{
	MakeCurrent(control, context);
	InitExtensions();
}

void wxGLRenderer::MakeCurrent(void *control, void *context)
{
	wxGLContext *ctx = static_cast<wxGLContext*>(context);
	ctx->SetCurrent(*static_cast<wxGLCanvas*>(control));
}

void wxGLRenderer::SwapBuffers(void *control)
{
	static_cast<wxGLCanvas*>(control)->SwapBuffers();
}

/// <summary>
/// Constructor.
/// </summary>
/// <param name="control">Control to render to</param>
/// <param name="renderer">The renderer for the control</param>
/// <param name="viewport">The viewport we are rendering</param>
wxControl2D::wxControl2D(wxGLCanvas *control, wxGLContext *context, wxGLRenderer *renderer, const Viewport &viewport) :
	Control2DBase(viewport, renderer)
{
	Control = control;
	Context = context;

	renderer->CreateContext(control, context);

	_drawingRenderer = new wxGLRenderer();

	_glRenderer = renderer;

	glEnable(GL_TEXTURE_2D);
	glEnable(GL_CULL_FACE);
	glEnable(GL_DEPTH_TEST);
	glFrontFace(GL_CW);

	if (!_supportShaders)
	{
		glEnable(GL_ALPHA_TEST);
		glAlphaFunc(GL_GEQUAL, 0.1f);
	}

	glClearColor(0.52f, 0.8f, 0.92f, 1.0f);
}

wxControl2D::~wxControl2D()
{
	delete _drawingRenderer;
}

/// <summary>
/// Get the handle for the control.
/// </summary>
void *wxControl2D::GetHandle() const
{
	return Control->GetHandle();
}

void wxControl2D::ResetValues()
{
	Renderer->MakeCurrent(Control, Context);
	Control2DBase::ResetValues();
}

void wxControl2D::control_SizeChanged(wxSizeEvent &e)
{
	Renderer->MakeCurrent(Control, Context);
	_drawingRenderer->SetupMatrices(e.GetSize().GetWidth(), e.GetSize().GetHeight());
	Renderer->PreloadChunks();
	Refresh();
}

void wxControl2D::control_MouseWheel(wxMouseEvent &e)
{
	MouseWheel(e.GetWheelRotation());
}

#if defined(__WXGTK__)
   #define HIDE_CURSOR wxSetCursor(wxCURSOR_BLANK)
   #define SHOW_CURSOR wxSetCursor(*wxSTANDARD_CURSOR)
#elif defined(__WXMSW__)
   #define HIDE_CURSOR ShowCursor(0)
   #define SHOW_CURSOR ShowCursor(1)
#endif

bool _cursorHidden = false;

void wxControl2D::control_MouseUp(wxMouseEvent &e)
{
	MouseButton button = (e.LeftDown() ? MouseButton_Left : e.RightDown() ? MouseButton_Right : MouseButton_Middle);
	MouseUp(Point2i(e.GetPosition().x, e.GetPosition().y), button);

	if (_cursorHidden)
	{
		SHOW_CURSOR;
		_cursorHidden = false;
	}
}

void wxControl2D::control_MouseMove(wxMouseEvent &e)
{
	MouseButton button = (e.LeftDown() ? MouseButton_Left : e.RightDown() ? MouseButton_Right : MouseButton_Middle);
	MouseMove(Point2i(e.GetPosition().x, e.GetPosition().y), button);

	if (_moving)
	{
		_pos = Point2i(GetWidth() / 2, GetHeight() / 2);
		Control->WarpPointer(GetWidth() / 2, GetHeight() / 2);
	}
}

void wxControl2D::control_MouseDown(wxMouseEvent &e)
{
	MouseButton button = (e.LeftDown() ? MouseButton_Left : e.RightDown() ? MouseButton_Right : MouseButton_Middle);
	MouseDown(Point2i(e.GetPosition().x, e.GetPosition().y), button);

	if (!_cursorHidden)
	{
		HIDE_CURSOR;
		_cursorHidden = true;
	}
}

void wxControl2D::control_Paint(wxPaintEvent &e)
{
#ifdef _DEBUG
	//wxStopWatch timer;
	//timer.Start();
#endif

	Renderer->MakeCurrent(Control, Context);

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	Draw();

	Renderer->SwapBuffers(Control);

#ifdef _DEBUG
	//timer.Pause();
	//auto v = timer.Time();
	//((wxFrame*)this->Control->GetParent())->SetTitle(wxString() << v);
#endif
}

/// <summary>
/// Refresh the control.
/// </summary>
void wxControl2D::Refresh()
{
	//wxPaintEvent e;
	//control_Paint(e);
	Control->Refresh();
}

/// <summary>
/// Get the width of the GDI control.
/// </summary>
int wxControl2D::GetWidth() const
{
	return Control->GetSize().x;
}

/// <summary>
/// Get the height of the GDI control.
/// </summary>
int wxControl2D::GetHeight() const
{
	return Control->GetSize().y;
}